package com.cms.cinema.query;

import com.cms.cinema.config.QueryConfig;
import com.mysql.cj.jdbc.exceptions.CommunicationsException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.StopWatch;

import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import java.sql.*;
import java.util.concurrent.CountDownLatch;

/**
 * QuerySql
 *
 * @author: chenfenghai
 * @version: 1.0
 * @date: 2020-03-24 11:02
 * @blame Team
 */
@Slf4j
public class QuerySql implements Runnable {

    public static final int IP_MAX_LENGTH = 15;
    private QueryConfig queryConfig;
    private CountDownLatch latch;

    public QuerySql(QueryConfig queryConfig, CountDownLatch latch){
        this.queryConfig = queryConfig;
        this.latch = latch;
    }

    /**
     * When an object implementing interface <code>Runnable</code> is used
     * to create a thread, starting the thread causes the object's
     * <code>run</code> method to be called in that separately executing
     * thread.
     * <p>
     * The general contract of the method <code>run</code> is that it may
     * take any action whatsoever.
     *
     * @see Thread#run()
     */
    @Override
    public void run() {
        try{
            while (!Query.ipVector.isEmpty()) {
                try {
                    execute(Query.ipVector.remove(0));
                }catch (Exception e){
                    log.error("", e);
                }
            }
        }catch (Exception ex){
            log.error("", ex);
        }finally {
            latch.countDown();
        }
    }

    private void execute(String ip){
        StopWatch stopWatch = new StopWatch(ip);
        stopWatch.start();
        String url = queryConfig.getUrl().replaceAll("\\{IP}", ip);
        Connection conn = null;
        PreparedStatement pstmt = null;
        try {
            // 初始化JDBC驱动并让驱动加载到jvm中
            Class.forName(queryConfig.getDriverClassName());
            // 创建数据库连接
            conn = DriverManager.getConnection(url, queryConfig.getUsername(), queryConfig.getPassword());
            pstmt = conn.prepareStatement(queryConfig.getSql());
            try (ResultSet rs = pstmt.executeQuery()) {
                int col = rs.getMetaData().getColumnCount();
                while (rs.next()) {
                    String outputScript = queryConfig.getOutputScript().replaceAll("\\{IP}", ip);
                    String outputFormat = queryConfig.getOutputFormat().replaceAll("\\{IP15}", StringUtils.rightPad(ip, IP_MAX_LENGTH));
                    outputFormat = outputFormat.replaceAll("\\{IP}", ip);
                    for (int i = 1; i <= col; i++) {
                        outputScript = outputScript.replaceAll("\\{" + rs.getMetaData().getColumnLabel(i) + "}", rs.getString(i));
                        outputFormat = outputFormat.replaceAll("\\{" + rs.getMetaData().getColumnLabel(i) + "}", rs.getString(i));
                    }
                    if(isOutput(outputScript)){
                        Query.outVector.add(outputFormat);
                    }else{
                        log.warn("表达式为: {}, 不进行输出到文件: {}", outputScript, outputFormat);
                    }
                }
            }
        }catch (CommunicationsException ce){
            stopWatch.stop();
            log.error("{}, running time (millis) = {}, 连接报错: Communications link failure",
                    StringUtils.rightPad(ip, IP_MAX_LENGTH), stopWatch.getTotalTimeMillis());
        }
        catch (Exception e) {
            stopWatch.stop();
            log.error("{}, running time (millis) = {}, 报错: {}",
                    StringUtils.rightPad(ip, IP_MAX_LENGTH), stopWatch.getTotalTimeMillis(), e.getMessage());
        }finally {
            try {
                if(pstmt != null){
                    pstmt.close();
                }
            }catch (Exception ignored){}
            try {
                if(conn != null){
                    conn.close();
                }
            }catch (Exception ignored){}
        }
    }

    /**
     ** 是否输出
     *
     * @param script 是否表达式
     * @return boolean
     */
    public static boolean isOutput(String script){
        try {
            if("true".equalsIgnoreCase(script.trim())){
                return true;
            }
            ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
            ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("js");
            Object result = scriptEngine.eval(script);
            if(result instanceof Boolean){
                return (Boolean)result;
            }
        }catch (Exception ex){
            log.error("", ex);
        }
        return false;
    }
}
